// -*- Mode: C++; c-basic-offset: 8; indent-tabs-mode: nil -*-
//-
// Copyright (c) 2010 Michael Smith. All rights reserved.
// 
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.
// 
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.

/// @file       decoder.h
/// @brief      ArduPilotMega binary protocol decoder

#include "protocol.h"

/// Callout registration structure for message receipt handlers.
struct message_handler {
        uint8_t         messageID;
        void            (* handler)(void *arg, uint8_t messageID, uint8_t messageVersion, void *messageData);
        void            *arg;
};

#define DEC_MESSAGE_TIMEOUT     100             ///< silence for 100ms means we have lost the link and should reset

// Internal messageID values
#define MSG_ANY                 0xfe            ///< wildcard for handlers interested in any message
#define MSG_NULL                0xff            ///< sentinel - never used in a message

/// @name Internal state machine phases
//@{
#define DEC_WAIT_P1      0
#define DEC_WAIT_P2      1
#define DEC_WAIT_HEADER  2
#define DEC_WAIT_PACKET  3
#define DEC_WAIT_SUM_A   4
#define DEC_WAIT_SUM_B   5
//@}

/// @class      Decoder
/// @brief      packet decode state machine
///
class Decoder {
public:
        Decoder(struct message_handler *handlerTable) :
                _phase          (DEC_WAIT_P1),
                _handlerTable   (handlerTable) {};

        /// Periodic incall
        ///
        /// Checks the serial port for bytes, feeds them to ::_kick
        ///
        void    poll(void);
private:
        /// Kick the state machine with a new byte
        ///
        /// @param inByte       newly received byte from the serial port
        void    _kick(uint8_t inByte);

        uint8_t                 _phase;         ///< state machine phase

        uint8_t                 _bytesIn;       ///< bytes received in the current phase
        uint8_t                 _bytesExpected; ///< bytes expected in the current phase
        uint8_t                 _sumA;          ///< sum of incoming bytes
        uint8_t                 _sumB;          ///< sum of _sumA values

        uint8_t                 _messageID;     ///< messageID from the packet being received
        uint8_t                 _messageVersion;///< messageVersion from the packet being received

        unsigned long           _lastReceived;  ///< timestamp of last byte reception

        struct message_handler   *_handlerTable; ///< callout table

        /// Incoming header/packet buffer
        union {
                uint8_t                  bytes[1];
                struct msg_packet_header header;
                union msg_payload        payload;
        } _buf;
};

